<?php
/**
 * 推送语音文件到设备示例
 * 
 * 使用0x30命令推送语音文件
 */

/**
 * 推送语音文件到设备
 * 
 * @param resource $socket 设备socket连接
 * @param string $deviceSn 设备序列号
 * @param string $voiceUrl 语音文件URL
 * @param string $fileName 文件名
 * @param string $md5 文件MD5校验码
 * @return bool
 */
function pushVoiceFile($socket, string $deviceSn, string $voiceUrl, string $fileName, string $md5 = ''): bool
{
    // 构建请求数据
    $data = [
        'deviceType' => 'F800W',
        'fileType' => '0',  // 0=单个语音文件，1=语音固件包
        'downloadUrl' => $voiceUrl,
        'name' => $fileName,
        'md5' => $md5
    ];
    
    $message = [
        'cmd' => 20,
        'message' => 'spSetSoundsFileReq',
        'messageId' => (string)time(),
        'sn' => $deviceSn,
        'data' => $data
    ];
    
    // 发送消息
    $jsonBody = json_encode($message, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    $bodyLen = strlen($jsonBody);
    
    // 构建头部（11字节）
    $header = 'OFZL';                           // 4字节标识
    $header .= pack('C', 1);                    // 1字节版本
    $header .= pack('C', 1);                    // 1字节数据类型
    $header .= pack('C', 0x30);                 // 1字节命令码（0x30）
    $header .= pack('V', $bodyLen);             // 4字节长度（小端序）
    
    // 发送数据
    $sent = @socket_write($socket, $header . $jsonBody, 11 + $bodyLen);
    
    if ($sent === false) {
        logMsg("[VOICE] Failed to send voice file push request");
        return false;
    }
    
    logMsg("[VOICE] Voice file push request sent: {$fileName} -> {$voiceUrl}");
    return true;
}

/**
 * 处理语音文件推送响应
 * 
 * @param array $data 响应数据
 * @return array
 */
function handleVoiceFileResponse(?array $data): array
{
    logMsg("[VOICE] Voice file push response received");
    
    return [
        'result' => 200,
        'desc' => 'Success',
        'message' => 'spSetSoundsFileRsp',
        'messageId' => $data['messageId'] ?? '',
        'data' => []
    ];
}

// ============================================
// 使用示例
// ============================================

/**
 * 示例1：推送单个语音文件
 */
function example_pushSingleVoice($socket, $deviceSn)
{
    // 语音文件URL（需要设备能访问）
    $voiceUrl = 'http://your-server.com/voice/checkin_start.mp3';
    $fileName = 'checkin_start.mp3';
    $md5 = md5_file('/path/to/local/checkin_start.mp3'); // 可选
    
    pushVoiceFile($socket, $deviceSn, $voiceUrl, $fileName, $md5);
}

/**
 * 示例2：批量推送所有签到语音文件
 */
function example_pushAllCheckinVoices($socket, $deviceSn)
{
    $voices = [
        [
            'url' => 'http://your-server.com/voice/checkin_start.mp3',
            'name' => 'checkin_start.mp3',
            'description' => '签到开始'
        ],
        [
            'url' => 'http://your-server.com/voice/checkin_end.mp3',
            'name' => 'checkin_end.mp3',
            'description' => '签到结束'
        ],
        [
            'url' => 'http://your-server.com/voice/checkin_duplicate.mp3',
            'name' => 'checkin_duplicate.mp3',
            'description' => '请勿重复刷脸'
        ],
        [
            'url' => 'http://your-server.com/voice/checkin_timeout.mp3',
            'name' => 'checkin_timeout.mp3',
            'description' => '签到超时作废'
        ]
    ];
    
    foreach ($voices as $voice) {
        pushVoiceFile($socket, $deviceSn, $voice['url'], $voice['name']);
        sleep(1); // 间隔1秒，避免设备处理不过来
    }
}

/**
 * 示例3：在设备登录成功后自动推送语音文件
 */
function example_pushVoiceOnLogin($socket, $deviceSn)
{
    // 设备登录成功后，推送语音文件
    logMsg("[VOICE] Device {$deviceSn} logged in, pushing voice files...");
    
    example_pushAllCheckinVoices($socket, $deviceSn);
}

// ============================================
// 集成到TCP服务器
// ============================================

/**
 * 在 simple_server.php 中添加以下代码：
 * 
 * 1. 在 handleLogin() 函数中，登录成功后推送语音文件：
 * 
 * function handleLogin(?array $data, string $peer): array
 * {
 *     // ... 原有登录逻辑 ...
 *     
 *     if ($loginSuccess) {
 *         // 推送语音文件
 *         global $clientSocket;
 *         example_pushAllCheckinVoices($clientSocket, $sn);
 *     }
 *     
 *     return $response;
 * }
 * 
 * 2. 在主循环中添加 0x31 命令处理：
 * 
 * case 0x31: // 语音文件推送响应
 *     $response = handleVoiceFileResponse($msgData);
 *     break;
 */

// ============================================
// 语音文件播放方式
// ============================================

/**
 * 方式1：推送语音文件后，在响应中指定播放
 * 
 * 在 snapshotFaceRsp 响应中添加：
 * 
 * {
 *   "data": {
 *     "voice_file": "checkin_start.mp3"  // 指定播放的语音文件名
 *   }
 * }
 * 
 * 设备收到后，播放对应的语音文件
 */

/**
 * 方式2：使用TTS文本转语音（推荐）
 * 
 * 在 snapshotFaceRsp 响应中添加：
 * 
 * {
 *   "data": {
 *     "voice_message": "李四，签到开始"  // 设备使用TTS播报
 *   }
 * }
 * 
 * 优点：
 * - 不需要预录语音文件
 * - 可以动态播报姓名、积分等信息
 * - 实现简单
 */

// ============================================
// 注意事项
// ============================================

/**
 * 1. 语音文件格式
 *    - 推荐格式：MP3、WAV
 *    - 采样率：16kHz 或 8kHz
 *    - 比特率：64kbps 或 128kbps
 * 
 * 2. 文件大小
 *    - 建议每个文件不超过 1MB
 *    - 语音时长不超过 10秒
 * 
 * 3. URL要求
 *    - 必须是设备能访问的HTTP/HTTPS地址
 *    - 建议使用内网地址，下载速度快
 * 
 * 4. MD5校验
 *    - 可选，但建议提供
 *    - 确保文件完整性
 * 
 * 5. 设备存储
 *    - 设备会将语音文件保存到本地
 *    - 下次播放时直接使用本地文件
 *    - 如果文件已存在且MD5相同，不会重复下载
 */

// ============================================
// 推荐方案
// ============================================

/**
 * 根据你的需求（动态播报姓名和积分），推荐使用：
 * 
 * 方案A：TTS文本转语音（最简单）⭐
 * - 在响应中返回 voice_message 字段
 * - 设备使用TTS引擎播报
 * - 已经在代码中实现
 * 
 * 方案B：混合方案
 * - 固定语音使用预录文件（音质好）
 * - 动态内容使用TTS（灵活）
 * - 例如："签到开始"用预录文件，姓名用TTS
 * 
 * 方案C：完全使用预录文件（不推荐）
 * - 需要为每个会员录制语音
 * - 工作量大，不灵活
 */

